#include "Lily_help.h"

typedef struct
{
    Tasks_def work;
    uint32_t period, tick;
} Li_timer_t;

typedef struct
{
    TasksArg_def work;
    uint32_t period, tick;
    void *arg;
} Li_timerArg_t;

typedef Li_timer_t *Li_timer;
typedef Li_timerArg_t *Li_timerArg;

static Li_List lily_timers = NULL;
static Li_List lily_timersArg = NULL;

#define quick_timer_len 16
static Tasks_def quick_timer[quick_timer_len];
int32_t quick_timer_count[quick_timer_len];
static char quick_timer_size = 0;

void li_new_timer(Tasks_def task, uint32_t period)
{
    Li_timer_t timerwork = {task, period, period};
    li_add(lily_timers, timerwork);
}
void li_new_timer_arg(TasksArg_def task, uint32_t period, void *arg)
{
    Li_timerArg_t timerwork = {task, period, period, arg};
    li_add(lily_timersArg, timerwork);
}
int32_t li_remove_timer(Tasks_def task)
{
    int32_t index;
    index = timer_find(task);
    if (index < 0)
        return -1;
    list_swap_out(lily_timers, index);
    return 0;
}
int32_t li_remove_timer_arg(TasksArg_def task, void *arg)
{
    int32_t index;
    index = timer_find_arg(task, arg);
    if (index < 0)
        return -1;
    list_swap_out(lily_timersArg, index);
    return 0;
}
int32_t timer_find(Tasks_def task)
{
    int32_t i;
    Li_timer ts = list_content(lily_timers, Li_timer_t);
    for (i = 0; i < lily_timers->count; i++)
    {
        if (ts[i].work == task)
        {
            return i;
        }
    }
    return -1;
}
int32_t timer_find_arg(TasksArg_def task, void *arg)
{
    int32_t i;
    Li_timerArg ts = list_content(lily_timersArg, Li_timerArg_t);
    for (i = 0; i < lily_timersArg->count; i++)
    {
        if (ts[i].work == task && ts[i].arg == arg)
        {
            return i;
        }
    }
    return -1;
}
void* timer_find_arg_iteration(TasksArg_def task, int* iter, int * out_period)
{
    if(*iter < 0)
        return NULL;
    int32_t i;
    Li_timerArg ts = list_content(lily_timersArg, Li_timerArg_t);
    for (i = *iter; i < lily_timersArg->count; i++)
    {
        if (ts[i].work == task)
        {
            *iter = i+1;
            *out_period = ts[i].period;
            return (ts[i].arg);
        }
    }
    *iter = -1;
    return NULL;
}
void timer_change_period(Tasks_def task, unsigned int newPer)
{
    int i;
    Li_timer ts = list_content(lily_timers, Li_timer_t);
    for (i = 0; i < lily_timers->count; i++)
    {
        if (ts[i].work == task)
        {
            ts[i].period = newPer;
            ts[i].tick = newPer;
            return;
        }
    }
}
void timer_arg_change_period(TasksArg_def task, void *arg, unsigned int newPer)
{
    int i;
    Li_timerArg ts = list_content(lily_timersArg, Li_timerArg_t);
    for (i = 0; i < lily_timersArg->count; i++)
    {
        if (ts[i].work == task && ts[i].arg == arg)
        {
            ts[i].period = newPer;
            ts[i].tick = newPer;
            return;
        }
    }
}

int32_t lily_tick()
{
    if ((_tp_rear + 1) % Tasks_LEN == _tp_front)
    {
        return -1;
    }
    int32_t i;
    Li_timer ts = list_content(lily_timers, Li_timer_t);
    for (i = 0; i < lily_timers->count; i++)
    {
        if (--(ts[i].tick) == 0)
        {
            ts[i].tick = ts[i].period;
            tp_addTask(ts[i].work);
        }
    }
    Li_timerArg tsArg = list_content(lily_timersArg, Li_timerArg_t);
    for (i = 0; i < lily_timersArg->count; i++)
    {
        if (--(tsArg[i].tick) == 0)
        {
            tsArg[i].tick = tsArg[i].period;
            tp_addTaskArg(tsArg[i].work, tsArg[i].arg);
        }
    }
    for (i = 0; i < quick_timer_size; i++)
    {
        if (--quick_timer_count[i] <= 0)
        {
            tp_addTask(quick_timer[i]);
            quick_timer_size--;
            quick_timer[i] = quick_timer[(int32_t)quick_timer_size];
            quick_timer_count[i--] = quick_timer_count[(int32_t)quick_timer_size];
        }
    }
    return 0;
}

int32_t li_new_timer_once(Tasks_def task, int32_t count)
{
    quick_timer[(int32_t)quick_timer_size] = task;
    quick_timer_count[(int32_t)quick_timer_size++] = count;
    if (quick_timer_size >= quick_timer_len)
    {
        quick_timer_size = 0;
        return -1;
    }
    return 0;
}
int32_t _quick_timer_change_count(Tasks_def timer, int32_t newCount)
{
    int32_t i;
    for (i = 0; i < quick_timer_size; i++)
    {
        if (quick_timer[i] == timer)
        {
            quick_timer_count[i] = newCount;
            return 0;
        }
    }
    return -1;
}
int32_t li_new_timer_once_count(Tasks_def timer, int32_t newCount)
{
    int32_t i;
    for (i = 0; i < quick_timer_size; i++)
    {
        if (quick_timer[i] == timer)
        {
            quick_timer_count[i] = newCount;
            return 0;
        }
    }
    return li_new_timer_once(timer, newCount);
}

static void _on_memory_reduction(void *private_data, void *arg)
{
    if (lily_timers)
        list_reduction(lily_timers);
    if (lily_timersArg)
        list_reduction(lily_timersArg);
}

void lily_timer_init()
{
    // timer
    lily_timers = new_list(sizeof(Li_timer_t), 4);
    if (!lily_timers)
    {
        lily_out("lily timers init failed!");
        return;
    }
    lily_timersArg = new_list(sizeof(Li_timerArg_t), 4);
    if (!lily_timersArg)
    {
        lily_out("lily timersArg init failed!");
        return;
    }
    event_register_to_tag("memReduction", NULL, _on_memory_reduction);
}